//
//  main.m
//  C09_函数指针
//
//  Created by dllo on 15/11/27.
//  Copyright © 2015年 dllo. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Student.h"

typedef int II;

typedef int (*FUN)(int, int);

/** 函数: 参数含有函数指针 */

int getValue(int, int, int (*)(int, int));
int getValue(int x, int y, int (*p)(int, int)){
    
    int value = p(x, y);
    return value;
  
}

/** 函数: 返回两个整数的乘积 */
int jiValue(int x, int y){
    
    return x * y;
}



/** 声明一个求两个数最大值的函数 */
int maxValue(int x, int y);

int maxValue(int x, int y){
    
    return x > y ? x : y;
}

/** 函数: 返回两个整数的和 */
int sumValue(int x, int y);

int sumValue(int x, int y){
    
    return x + y;
}

void printHello();
void printHello(){
    printf("Hello\n");
   
}

/** (4). 定义函数指针调用排序函数 */
void paixu(int array[], int count);
void paixu(int array[], int count){
    int temp = 0;
    for (int i = 0; i < count - 1; i++) {
        for (int j = 0; j < count - i - 1; j++) {
            if (array[j] > array[j + 1]) {
                temp = array[j];
                array[j] = array[j + 1];
                array[j + 1] = temp;
            }
        }
    }
}

/** 函数:排序(指针版本) */
void paixu2(int *arr, int count){
    int temp = 0;
    for (int i = 0; i < count - 1; i++) {
        for (int j = 0; j < count - i - 1; j++) {
            if (*(arr + j) > *(arr + j + 1)) {
                temp = *(arr + j);
                *(arr + j) = *(arr + j + 1);
                *(arr + j + 1) = temp;
            }
        }
    }
    for (int i = 0; i < count; i++) {
        printf("%d ", *(arr + i));
    }
}

/** 定义一个函数指针, 调用遍历输出数组的函数 */
void print(int *array, int count);
void print(int *array, int count){
    
    for (int i = 0; i < count; i++) {
        printf("%d ", *(array + i));
    }
    
}



int main(int argc, const char * argv[]) {

#pragma mark - 知识点1 函数指针定义和使用
#if 0
    /** 函数指针: 指针指向函数(代码区) */
    maxValue(3, 5);
    printf("max = %d\n", maxValue(3, 5));
    
    /** 查看代码区,查看maxValue, sumTwoNumber函数的内存地址 */
    
    printf("max add : %p\n", maxValue);
    printf("sum add : %p\n", sumValue);
#endif
    /** 重点: 如何确定函数指针类型!!!
     * 
     * 技巧1: 函数声明部分, 将函数名去掉就是函数指针类型
     *
     *      函数指针变量如何定义
     * 技巧2: 函数声明部分, 将函数名替换成(*p), 其中的p是指针变量名
     */
#if 0
    int (*p)(int x, int y) = NULL;
    
    /** 上面语法说明:
     * 指针类型: int (*)(int x, int y)
     * 指针变量: p
     * 指针变量值: NULL
     */
    
    int *p2 = NULL;   /** int a = 100; */
    
    int (*arr)[5] = NULL;  /** int arr[5] */
#endif
#if 0   /** 指针数组, 数组指针. 容易混淆的两个概念*/
    {
        int *array[5] = {};  /**< 指针数组, 其中array是数组名, [5]数组元素个数, int *: 数组中存放的指针的指针类型  */
        int (*array2)[5] = NULL; /** 数组指针, 其中array2是指针的变量名, int * [5]: 是指针类型. 
                                  * array2 + 1, 访问下一个 20 字节的内容*/
    }
#endif
    
#if 0
    /** 函数指针赋值 */
    int (*p)(int, int) = NULL;
    p = maxValue;    /** 将指针指向了maxValue函数代码的首地址. 注意: 指针类型和函数的类型要一致(包括返回值和参数列表) */
    
    
    /** 通过 函数指针 调用函数 */
    
    p(3, 5);
    printf("result : %d\n", p(3, 5));
    
    p = sumValue;     /** 将p指向sumValue函数代码段首地址 */
    printf("result : %d\n", p(3,5));
#endif
    
#pragma mark ** 练习
#if 0  //(3) 定义函数指针指向printHello函数. 并用函数指针调用函数
void (*p1)() = NULL;  /** 定义一个指针变量 */
    p1 = printHello;  /** 变量赋值 */
    p1();  /** 通过指针调用函数 */
#endif
    
#if 0 //(1) 定义可以指向系统strlen函数的指针
    size_t	 (*p1)(const char *) = strlen;
    
    char string[] = "iphone";
    p1(string);
    printf("%ld\n", p1(string));
#endif
    
#if 0 //(2) 定义一个指向系统strcpy函数的指针
    {
        char	*(*p)(char *, const char *) = strcpy;
        
        char string1[10] = "";
        char string2[] = "ios";
        p(string1, string2);
        printf("%s\n", p(string1, string2));
        
    }
#endif
    
#if 0  //(4) 定义函数指针调用排序函数, 定义一个函数指针, 调用遍历输出数组的函数
    {
        void (*p)(int *, int) = NULL;

        
        int array1[5] = {1, 3, 5, 6, 4};
        p = paixu;   /** 指针指向排序函数 */
        p(array1, 5);
        
        p = print;  /** 指针指向输出数组函数 */
        p(array1, 5);

        printf("\n");
        
        
//        p = paixu2;
//        p(array1, 5);
//        printf("\n");
       
    }
#endif
    
#if 0 // (5) 定义两个 函数 ,一个求 最大值,一个 求和,输入maxValue或sumV分别求 3 , 5的最大值或和
    {
        /** 定义字符串用于接受控制台输入的字符串 */
        char string[20] = "";
        int (*p)(int , int) = NULL;
        printf("请输入函数(maxValue或者sumValue):");
        scanf("%s", string);
        
        /** 根据输入不同的字符串, 指针指向不同的函数 */
        if (strcmp(string, "maxValue") == 0) {
            p = maxValue;
        }
        else if (strcmp(string, "sumValue") == 0){
            p = sumValue;
        } else {
            printf("无效字符串");
        }
        
        /** 通过指针调用函数, 输出结果 */
        if (p) {              /**< 当指针不为空时 */
            printf("%d\n", p(3, 5));
        }
        
    }
#endif

#pragma mark - 知识点2 函数回调(callback)
    
    /** 本质: 函数指针作为函数的参数 */
#if 0
    /** 求两个数最大值 */
    int max = getValue(3, 5, maxValue);
    printf("max = %d\n", max);
    
    /** 求两个数的和 */
    int sum = getValue(3, 5, sumValue);
    printf("sum = %d\n", sum);
    
    /** 求两个数的乘积 */
    int ji = getValue(3, 5, jiValue);
    printf("ji = %d\n", ji);
#endif
 
#pragma mark ** 练习
    
    /** 写一函数查找成绩90分以上的学员,使用回调函数在姓名后加上"高富帅"
     * 
     * 使用同一个函数,查找成绩60分以下学员,使用回调函数使分数加5分 */
    
    Student stu1 = {"zhangQiang", 20, 91};
    Student stu2 = {"wangYan", 21, 90};
    Student stu3 = {"liXiang", 19, 97};
    Student stu4 = {"PanLong", 22, 92};
    Student stu5 = {"wangQiang", 40, 59};

    /** 定义一个结构体数组 */
    Student arrStu[5] = {stu1, stu2, stu3, stu4, stu5};
#if 0
    /** 调用查找学生函数 */
    selectedStudents(arrStu, 5, changeName);
    
    /** 调用遍历输出学生信息 函数 */
    infoOfStudents(arrStu, 5);
    
    selectedStudents(arrStu, 5, changeScore);  /**< 此时调用函数时, 还是分数 >90 分的学生分数+5分, 因为selectedStudents函数内的判断条件是固定的(即 stu.score > 90). 那么如何使判断条件是动态变化的呢? 这就是下面动态排序的原理 详见动态排序 */
#endif
    
    
    
    
    
    
    
    
#pragma mark - 知识点3 动态排序
    
    
    
#pragma mark ** 练习
    
    /** 按照姓名排序 */
    sortArr(arrStu, 5, cmpName);
    infoOfStudents(arrStu, 5);
    printf("--------------------\n");
    
    /** 按照分数排序 */
    sortArr(arrStu, 5, cmpScore);
    infoOfStudents(arrStu, 5);
    printf("--------------------\n");
    
    /** 按照年龄排序 */
    sortArr(arrStu, 5, cmpAge);
    infoOfStudents(arrStu, 5);
    
    
    
#pragma mark - 知识点4 函数指针类型重定义(typedef)
    
    FUN point = maxValue;
    point(3, 5);
    printf("%d\n", point(3, 5));
    
   
#pragma mark ** 练习
    

    
    return 0;
}
